import { _decorator, Component, Node, Input, input, RigidBody2D, Vec2, Collider2D, Contact2DType, Prefab, Vec3, instantiate, Label, Director } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('Game')
export class Game extends Component {
  @property({ type: Node })
  private ballNode: Node = null!; // 球节点

  @property({ type: Node })
  private blocksNode: Node = null!; // 地块集合节点
  @property({ type: Prefab })
  private blockPrefab: Prefab = null!; // 地板预制体

  @property({ type: Label })
  private scoreLabel: Label = null!; // 得分节点

  private score: number = 0; // 得分
  private bounceSpeed: number = 0; // 球第一次落地的速度
  private gameStatus: number = 0; // 游戏状态 【1-开始，2-结束】
  private blockGap: number = 250; // 地板之间的空隙间距

  protected onLoad(): void {
   
  }
  start() {
    input.on(Input.EventType.TOUCH_START, this.touchBall, this);
    this.handleCollision();
    this.ballNode.position = new Vec3(-250, 200, 0); // 小球初始位置
    this.initBlock();
  }

  update(deltaTime: number) {
    if (this.gameStatus === 1) {
      this.moveAllBlock(deltaTime);
    }
  }
  protected onDestroy(): void {
    input.off(Input.EventType.TOUCH_START, this.touchBall, this);
  }

  // ** ---------- 地板 ---------- **
  //   初始化地板
  initBlock() {
    let posX: number = 0;
    for (let i = 0; i < 5; i++) {
      if (i == 0) {
        posX = this.ballNode.position.x; // 第一块地板 生成的位置在球的下方
      } else {
        posX += this.blockGap; // 其他地板的位置 = 当前小球下落的位置 + 地板间隙距离
      }
      this.createBlock(new Vec3(posX, 0, 0));
    }
  }

  //  创建地板
  createBlock(pos: Vec3) {
    // 实例化预制体
    let blockNode = instantiate(this.blockPrefab);
    blockNode.position = pos; // 当前生成的地板预制体的位置
    this.blocksNode.addChild(blockNode);  // 将预制体block节点 添加到 blocks集合节点下，成为它的子节点

  }

  //   地板移动 - 让地板反向移动实现小球正向移动的视觉效果
  moveAllBlock(dt: number) {
    let speed = -300 * dt; // 移动速度 - 地板反向所以设置负数

    for (let item of this.blocksNode.children) {
      let pos = item.position.clone(); // 克隆当前向量
      pos.x += speed;
      item.position = pos;

      this.checkBlockIsOut(item); // 检测地板是否溢出屏幕
    }
  }
  // 检测地板是否溢出屏幕
  checkBlockIsOut(block:Node) {
    // 当最后一块地板溢出屏幕后，将该地板的坐标修改为下一块地板出现的位置 【 项目720*1280;左右各360;上下各590】

    if (block.position.x < -400) { 
      let nextBlockPosX = this.getLastBlockPosX() + this.blockGap;

      // 增加地板Y坐标的位置，增加随机趣味
      let nextBlockPosY = (Math.random() > 0.5 ? 1 : -1) * (10 + Math.random() * 40);

      // 改变地板的出现位置
      block.position = new Vec3(nextBlockPosX, nextBlockPosY);

    //   跳过一个地板就增加得分
    this.increaseScore()
    }

    // 小球掉出屏幕
    if (this.ballNode.position.y < -700) {
      this.gameStatus = 2;
      Director.instance.loadScene('Game'); // 重新加载场景
    }
  }

  // 获取最后一块地板的X轴位置
  getLastBlockPosX(): number {
    let lastBlockPosX: number = 0;

    // 遍历所有地块，当地块x坐标大于 最后地板坐标值时，当前地板坐标值赋值给最后地板变量
    for (let item of this.blocksNode.children) {
      if (item.position.x > lastBlockPosX) {
        lastBlockPosX = item.position.x;
      }
    }
    return lastBlockPosX;
  }

  // ** ---------- 地板 End---------- **

  increaseScore(){
    this.score += 1;
    this.scoreLabel.string = this.score.toString();
  }

  // 触碰小球 - 或屏幕
  touchBall() {
    // 球没有第一次触碰到地板时，不执行后面逻辑
    if (this.bounceSpeed === 0) return false;

    // 获取小球节点上的刚体组件
    let rigidbody = this.ballNode.getComponent(RigidBody2D);

    const SPEED = -this.bounceSpeed * 1.5; // 设定球下落速度 = 反弹速度 * 1.5倍系数
    // [ linearVelocity - 刚体在世界坐标下的线性速度]
    rigidbody.linearVelocity = new Vec2(0, SPEED); // 实现点击后小球下落效果

    this.gameStatus = 1; // 游戏开始
  }

  // 碰撞回调
  handleCollision() {
    // 获取球节点上的碰撞体组件
    let collider = this.ballNode.getComponent(Collider2D);
    // 获取球节点上的刚体组件
    let rigidbody = this.ballNode.getComponent(RigidBody2D);

    collider.on(
      Contact2DType.BEGIN_CONTACT,
      () => {
        console.log('碰撞了');

        // 记录并设置小球在碰撞地板时的速度为第一次下落的速度，从而实现小球不会因为每次碰撞的速度不同，导致反弹的高度出现变化【即保持反弹的高度始终为第一次反弹的高度】
        if (this.bounceSpeed === 0) {
          this.bounceSpeed = Math.abs(rigidbody.linearVelocity.y);
        } else {
          rigidbody.linearVelocity = new Vec2(0, this.bounceSpeed);
        }
      },
      this
    );
  }
}
